package top.azusall.securitydemo.util;


import com.alibaba.fastjson2.JSON;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import top.azusall.common.exception.JwtInvalidException;
import top.azusall.securitydemo.common.MyUserDetail;


import java.text.ParseException;
import java.time.Instant;
import java.util.UUID;

/**
 * @author houmo
 */
@Slf4j
public class JwtUtil {


    private JwtUtil() {
    }

    /**
     * 过期时间 sec
     */
    private static final int EXPIRE_TIME = 3600;
    /**
     * 刷新时间 sec
     */
    private static final int REFRESH_TIME = 1800;
    private static final String SECRET = "huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0huomoe0";

    /**
     * 生成jwt
     */
    public static String generateJwt(MyUserDetail userDetail) {
        JWSHeader jwsHeader =
                new JWSHeader
                        // 加密算法
                        .Builder(JWSAlgorithm.HS512)
                        // 静态常量
                        .type(JOSEObjectType.JWT)
                        .build();

        // 密码置为空
        userDetail.getUser().setPassword(null);

        Claim security = Claim.builder()
                .sub("security")
                .iat(System.currentTimeMillis())
                .jti(UUID.randomUUID().toString())
                .exp(Instant.now().plusSeconds(EXPIRE_TIME).toEpochMilli())
                .myUserDetail(userDetail)
                .build();


        Payload payload = new Payload(JSON.toJSONString(security));

        JWSObject jwsObject = new JWSObject(jwsHeader, payload);
        JWSSigner jwsSigner;


        try {
            jwsSigner = new MACSigner(SECRET);
            // 进行签名（根据前两部分生成第三部分）
            jwsObject.sign(jwsSigner);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        return jwsObject.serialize();
    }

    public static boolean isRefresh(Claim claim) {
        return System.currentTimeMillis() > claim.getIat() + REFRESH_TIME * 1000;
    }


    /**
     * 校验jwt
     */
    public static Claim verifyJwt(String token) {
        try {
            JWSObject jwsObject = JWSObject.parse(token);
            //创建HMAC验证器
            JWSVerifier jwsVerifier = new MACVerifier(SECRET);

            // 校验失败或者过期抛异常
            if (!jwsObject.verify(jwsVerifier)) {
                throw new JwtInvalidException("token签名不合法!");
            }

            String payload = jwsObject.getPayload().toString();
            log.info("payload:{}", payload);
            Claim claim = JSON.parseObject(payload, Claim.class);

            if (claim.getMyUserDetail() == null) {
                throw new JwtInvalidException("token载荷不合法!");
            }

            return claim;
        } catch (ParseException | JOSEException e) {
            log.error(e.getMessage());
        }
        return null;
    }



    /**
     * jwt payload
     *
     * @author houmo
     */
    @Builder
    @Getter
    static
    public class Claim {
        /**
         * 主题
         */
        private String sub;
        /**
         * 签发时间
         */
        private Long iat;
        /**
         * 过期时间
         */
        private Long exp;
        /**
         * JWT ID
         */
        private String jti;
        /**
         * 用户信息
         */
        private MyUserDetail myUserDetail;

    }
}
